﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using NUnit.Framework;
using LinqtoCRM.Tests.CRM;

namespace LinqtoCRM.Tests
{
    [TestFixture]
    public class QueryTests : LinqtoCRMTests
    {
        [Test]
        public void TestAllContactsQuery() 
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           select c;
            AssertXmlEquals(expectedXml, contacts);
        }

        [Test]
        public void TestContactIdQuery()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           select new { c.contactid};
            AssertXmlEquals(expectedXml, contacts);
        }

        [Test]
        public void TestContactsQueryWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter></entity></fetch>";
            
            var contactsNamedScott = from c in provider.Linq<contact>()
                                     where c.firstname == "Scott"
                                     select c;
            AssertXmlEquals(expectedXml, contactsNamedScott);
        }

        [Test]
        public void TestChainedContactsQuery()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           select c;
            var contactsNamedScottChained = from c in contacts
                                     where c.firstname == "Scott"
                                     select c;
            AssertXmlEquals(expectedXml, contactsNamedScottChained);
        }

        [Test]
        public void TestWhereBinaryExpression()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <all-attributes />
                        <filter>
                            <condition attribute=""firstname"" operator=""eq"" value=""Scott"" />
                            <condition attribute=""lastname"" operator=""eq"" value=""Scott"" />
                        </filter>
                    </entity>
                </fetch>"; 
            
            var contactsNamedScottScott = from c in provider.Linq<contact>()
                                     where c.firstname == "Scott" && c.lastname == "Scott"
                                     select c;
            AssertXmlEquals(expectedXml, contactsNamedScottScott);
        }

        [Test]
        public void TestMultipleWhereCalls()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <all-attributes />
                        <filter>
                            <condition attribute=""firstname"" operator=""eq"" value=""Scott"" />
                            <condition attribute=""lastname"" operator=""eq"" value=""Scott"" />
                        </filter>
                    </entity>
                </fetch>";

            var contactsNamedScottScott = from c in provider.Linq<contact>()
                                          where c.firstname == "Scott"
                                          where c.lastname == "Scott"
                                          select c;
            AssertXmlEquals(expectedXml, contactsNamedScottScott);
        }

        [Test]
        [Category("StringOperations")]
        public void TestContains()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"like\" value=\"%Scott%\" /></filter></entity></fetch>";

            var contactsContainingScott = from c in provider.Linq<contact>()
                                     where c.firstname.Contains("Scott")
                                     select c;
            AssertXmlEquals(expectedXml, contactsContainingScott);
        }

        [Test]
        [Category("StringOperations")]
        public void TestStartsWith()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"like\" value=\"Scott%\" /></filter></entity></fetch>";

            var contactsStartingWithScott = from c in provider.Linq<contact>()
                                     where c.firstname.StartsWith("Scott")
                                     select c;
            AssertXmlEquals(expectedXml, contactsStartingWithScott);
        }

        [Test]
        [Category("StringOperations")]
        public void TestEndsWith()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"like\" value=\"%Scott\" /></filter></entity></fetch>";

            var contactsEndingWithScott = from c in provider.Linq<contact>()
                                     where c.firstname.EndsWith("Scott")
                                     select c;
            AssertXmlEquals(expectedXml, contactsEndingWithScott);
        }

        [Test]
        [Category("StringOperations")]
        public void TestEquals()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"like\" value=\"Scott\" /></filter></entity></fetch>";

            var contactsNamedScott = from c in provider.Linq<contact>()
                                     where c.firstname.Equals("Scott")
                                     select c;
            AssertXmlEquals(expectedXml, contactsNamedScott);
        }

        [Test]
        public void TestOrderBy()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /></entity></fetch>";
            var contactsOrderedByFirstname = from c in provider.Linq<contact>()
                                             orderby c.firstname
                                             select c;
            AssertXmlEquals(expectedXml, contactsOrderedByFirstname);
        }

        [Test]
        public void TestOrderByDesc()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" descending=\"true\" /></entity></fetch>";
            var contactsOrderedByFirstname = from c in provider.Linq<contact>()
                                             orderby c.firstname descending
                                             select c;
            AssertXmlEquals(expectedXml, contactsOrderedByFirstname);
        }

        [Test]
        public void TestOrderByWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter></entity></fetch>";
            var contactsOrderedByFirstname = from c in provider.Linq<contact>()
                                             orderby c.firstname
                                             where c.firstname == "Scott"
                                             select c;
            AssertXmlEquals(expectedXml, contactsOrderedByFirstname);
        }

        [Test]
        public void TestJoin()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contactsJoinedOnAccounts = from c in provider.Linq<contact>()
                                           join a in provider.Linq<account>()
                                           on c.parentcustomerid.Value equals a.accountid.Value
                                           select c;
            AssertXmlEquals(expectedXml, contactsJoinedOnAccounts);
        }

        [Test]
        public void TestJoinOrderBy()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contactsJoinedOnAccountsOrdered = from c in provider.Linq<contact>()
                                           join a in provider.Linq<account>()
                                           on c.parentcustomerid.Value equals a.accountid.Value
                                           orderby c.firstname
                                           select c;
            AssertXmlEquals(expectedXml, contactsJoinedOnAccountsOrdered);
        }


        [Test]
        public void TestJoinWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contactsNamedScottJoinedOnAccounts = from c in provider.Linq<contact>()
                                                  join a in provider.Linq<account>()
                                                  on c.parentcustomerid.Value equals a.accountid.Value
                                                  where c.firstname == "Scott"
                                                  select c;
            AssertXmlEquals(expectedXml, contactsNamedScottJoinedOnAccounts);
        }


        [Test]
        public void TestJoinOrderByWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contactsNamedScottJoinedOnAccountsOrdered = from c in provider.Linq<contact>()
                                                  join a in provider.Linq<account>()
                                                  on c.parentcustomerid.Value equals a.accountid.Value
                                                  orderby c.firstname
                                                  where c.firstname == "Scott"
                                                  select c;
            AssertXmlEquals(expectedXml, contactsNamedScottJoinedOnAccountsOrdered);
        }

        [Test]
        public void TestJoinOrderByDoubleWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /><condition attribute=\"lastname\" operator=\"eq\" value=\"Scott\" /></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contactsNamedScottScottJoinedOnAccountsOrdered = from c in provider.Linq<contact>()
                                                            join a in provider.Linq<account>()
                                                            on c.parentcustomerid.Value equals a.accountid.Value
                                                            orderby c.firstname
                                                            where c.firstname == "Scott" && c.lastname == "Scott"
                                                            select c;
            AssertXmlEquals(expectedXml, contactsNamedScottScottJoinedOnAccountsOrdered);
        }

        [Test]
        public void TestPagingFirstTen()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><all-attributes /></entity></fetch>";
            var firstTenContacts = (from c in provider.Linq<contact>()
                                   select c).Skip(0).Take(10);
            AssertXmlEquals(expectedXml, firstTenContacts);
        }

        [Test]
        public void TestPagingSecondTen()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\" page=\"2\"><entity name=\"contact\"><all-attributes /></entity></fetch>";
            var secondTenContacts = (from c in provider.Linq<contact>()
                                    select c).Skip(10).Take(10);
            AssertXmlEquals(expectedXml, secondTenContacts);
        }

        [Test]
        public void TestPagingFirstTenNineSkipped()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><all-attributes /></entity></fetch>";
            var firstTenContactsNineSkipped = (from c in provider.Linq<contact>()
                                    select c).Skip(9).Take(10);
            AssertXmlEquals(expectedXml, firstTenContactsNineSkipped);
        }

        [Test]
        public void TestPagingFirstTenWithWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter></entity></fetch>";
            var firstTenContactsNamedScott = (from c in provider.Linq<contact>()
                                    where c.firstname == "Scott"
                                    select c).Skip(0).Take(10);
            AssertXmlEquals(expectedXml, firstTenContactsNamedScott);
        }

        [Test]
        public void TestPagingFirstTenOrdered()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /></entity></fetch>";
            var firstTenContactsOrdered = (from c in provider.Linq<contact>()
                                              orderby c.firstname
                                              select c).Skip(0).Take(10);
            AssertXmlEquals(expectedXml, firstTenContactsOrdered);
        }

        [Test]
        public void TestPagingFirstTenJoined()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><all-attributes /><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var firstTenContactsJoined = (from c in provider.Linq<contact>()
                                           join a in provider.Linq<account>()
                                           on c.parentcustomerid.Value equals a.accountid.Value
                                           select c).Skip(0).Take(10);
            AssertXmlEquals(expectedXml, firstTenContactsJoined);
        }

        [Test]
        public void TestOrderByThenBy() 
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /><order attribute=\"contactid\" /></entity></fetch>";
            var contactsOrderedByFirstname = from c in provider.Linq<contact>()
                                             orderby c.firstname, c.contactid
                                             select c;
            AssertXmlEquals(expectedXml, contactsOrderedByFirstname);
        }

        [Test]
        public void TestOrderByDescendingThenByDescending()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" descending=\"true\" /><order attribute=\"contactid\" descending=\"true\" /></entity></fetch>";
            var contactsOrderedByFirstnameDescendingThenByContactidDescending = from c in provider.Linq<contact>()
                                             orderby c.firstname descending, c.contactid descending
                                             select c;
            AssertXmlEquals(expectedXml, contactsOrderedByFirstnameDescendingThenByContactidDescending);
        }

        [Test]
        public void TestOrderByThenByDescending()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /><order attribute=\"contactid\" descending=\"true\" /></entity></fetch>";
            var contactsOrderedByFirstnameThenByContactidDescending = from c in provider.Linq<contact>()
                                             orderby c.firstname, c.contactid descending
                                             select c;
            AssertXmlEquals(expectedXml, contactsOrderedByFirstnameThenByContactidDescending);
        }

        [Test]
        public void TestOrderByDescendingThenBy()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" descending=\"true\" /><order attribute=\"contactid\" /></entity></fetch>";
            var contactsOrderedByFirstnameDescendingThenByContactid = from c in provider.Linq<contact>()
                                             orderby c.firstname descending, c.contactid 
                                             select c;
            AssertXmlEquals(expectedXml, contactsOrderedByFirstnameDescendingThenByContactid);
        }

        [Test]
        public void TestOrderByThenByThenBy()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><order attribute=\"firstname\" /><order attribute=\"lastname\" /><order attribute=\"contactid\" /></entity></fetch>";
            var contactsOrderedByFirstnameLastnameContactid = from c in provider.Linq<contact>()
                                                                      orderby c.firstname, c.lastname, c.contactid
                                                                      select c;
            AssertXmlEquals(expectedXml, contactsOrderedByFirstnameLastnameContactid);
        }

        [Test]
        public void TestCount()
        {
            int expectedCount =2;
            var count = (from c in provider.Linq<contact>() select c).Count();

            Assert.AreEqual(expectedCount, count);

        }

        [Test]
        public void TestEntityPopulation() 
        {
            var contacts = provider.Linq<contact>().ToList();            
        }

        [Test]
        public void TestGreaterThan()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"statuscode\" operator=\"gt\" value=\"1\" /></filter></entity></fetch>";
            var contactsWithStatuscodeGreaterThanOne = from c in provider.Linq<contact>()
                                                              where c.statuscode.Value > 1
                                                              select c;
            AssertXmlEquals(expectedXml, contactsWithStatuscodeGreaterThanOne);
        }

        [Test]
        public void TestLessThan()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"statuscode\" operator=\"lt\" value=\"10\" /></filter></entity></fetch>";
            var contactsWithStatuscodeLessThanTen = from c in provider.Linq<contact>()
                                                              where c.statuscode.Value < 10
                                                              select c;
            AssertXmlEquals(expectedXml, contactsWithStatuscodeLessThanTen);
        }

        [Test]
        public void TestLessThanOrEqual()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"statuscode\" operator=\"le\" value=\"10\" /></filter></entity></fetch>";
            var contactsWithStatuscodeLessThanOrEqualTen = from c in provider.Linq<contact>()
                                                       where c.statuscode.Value <= 10
                                                       select c;
            AssertXmlEquals(expectedXml, contactsWithStatuscodeLessThanOrEqualTen);
        }

        [Test]
        public void TestGreaterThanOrEqual()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"statuscode\" operator=\"ge\" value=\"1\" /></filter></entity></fetch>";
            var contactsWithStatuscodeGreaterThanOrEqualOne = from c in provider.Linq<contact>()
                                                       where c.statuscode.Value >= 1
                                                       select c;
            AssertXmlEquals(expectedXml, contactsWithStatuscodeGreaterThanOrEqualOne);
        }

        [Test]
        public void TestNotEqual()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"statuscode\" operator=\"ne\" value=\"1\" /></filter></entity></fetch>";
            var contactsWithStatuscodeNotEqualToOne = from c in provider.Linq<contact>()
                                                              where c.statuscode.Value != 1
                                                              select c;
            AssertXmlEquals(expectedXml, contactsWithStatuscodeNotEqualToOne);
        }

        /// <summary>
        /// Issue #5390 
        /// Where clauses on linked entity attributes fail
        /// </summary>
        [Test]
        public void TestJoinWhereOnJoinedSelectOther()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\"><filter><condition attribute=\"name\" operator=\"like\" value=\"%Scott%\" /></filter></link-entity></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           join a in provider.Linq<account>()
                           on c.parentcustomerid.Value equals a.accountid.Value
                           where a.name.Contains("Scott")
                           select c;
            AssertXmlEquals(expectedXml, contacts);
        }

		/// <summary>
		/// Issue #5844 / steffana
		/// Where clause on statecode fails
		/// </summary>
		[Test]
		public void TestStateCodeActiveQuery()
		{
			string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"statecode\" operator=\"eq\" value=\"0\" /></filter></entity></fetch>";
			var activeContacts = from c in provider.Linq<contact>()
			                     where c.statecode.Value == ContactState.Active
			                     select c;
            AssertXmlEquals(expectedXml, activeContacts);
		}

		/// <summary>
		/// steffana
		/// Where clauses on linked entity attributes fail with multiple conditions on both entities
		/// </summary>
		[Test]
		public void TestJoinWhereOnBoth()
		{
			string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"fullname\" operator=\"eq\" value=\"scott\" /></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\"><filter><condition attribute=\"name\" operator=\"like\" value=\"%Scott%\" /></filter></link-entity></entity></fetch>";
			var contacts = from c in provider.Linq<contact>()
						   join a in provider.Linq<account>()
						   on c.parentcustomerid.Value equals a.accountid.Value
						   where c.fullname == "scott" && a.name.Contains("Scott")
						   select c;
            AssertXmlEquals(expectedXml, contacts);
		}

        /// <summary>
        /// Where clauses on multiple linked entities must be associated to the right entities
        /// </summary>
        [Test]
        public void TestJoinMultipleWhereOnAll()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <all-attributes />
                        <filter><condition attribute=""fullname"" operator=""eq"" value=""scott"" /></filter>
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"">
                            <filter><condition attribute=""name"" operator=""like"" value=""%Scott%"" /></filter>
                            <link-entity name=""businessunit"" from=""businessunitid"" to=""owningbusinessunit"">
                                <filter><condition attribute=""name"" operator=""eq"" value=""bu"" /></filter>
                            </link-entity>
                        </link-entity>
                    </entity>
                </fetch>";
            var contacts = from c in provider.Linq<contact>()
                           join a in provider.Linq<account>()
                           on c.parentcustomerid.Value equals a.accountid.Value
                           join b in provider.Linq<businessunit>()
                           on  a.owningbusinessunit.Value equals b.businessunitid.Value
                           where c.fullname == "scott" && a.name.Contains("Scott") && b.name == "bu"
                           select c;
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// Where clauses on multiple linked entities must be associated to the right entities
        /// Multiple joins cause trasparent identifiers to the resulting Expression
        /// </summary>
        [Test]
        public void TestJoinMultipleWhereGuidComparison()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""product"">
                    <all-attributes />
                    <filter>
                      <condition attribute=""statecode"" operator=""eq"" value=""0"" />
                    </filter>
                    <link-entity name=""productpricelevel"" from=""productid"" to=""productid"">
                      <link-entity name=""salesorder"" from=""pricelevelid"" to=""pricelevelid"">
                        <filter>
                          <condition attribute=""salesorderid"" operator=""eq"" value=""00000000-0000-0000-0000-000000000000"" />
                        </filter>
                      </link-entity>
                    </link-entity>
                  </entity>
                </fetch>
                ";

            var types = from pr in provider.Linq<product>()
                        join pl in provider.Linq<productpricelevel>() on pr.productid.Value equals pl.productid.Value
                        join order in provider.Linq<salesorder>() on pl.pricelevelid.Value equals order.pricelevelid.Value
                        where pr.statecode.Value == 0 && order.salesorderid.Value == Guid.Empty
                        select pr;
            AssertXmlEquals(expectedXml, types);
        }

		/// <summary>
		/// Issue #5818 / steffana
		/// Where clause on DateTime fails
		/// </summary>
		[Test]
		public void TestDateEqual()
		{
			string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"createdon\" operator=\"eq\" value=\"2008-09-02T00:00:00\" /></filter></entity></fetch>";
			var contactsCreatedOnDate = from c in provider.Linq<contact>()
			                           where c.createdon.UserTime == new DateTime(2008, 09, 02)
			                           select c;
            AssertXmlEquals(expectedXml, contactsCreatedOnDate);
		}

		/// <summary>
		/// steffana
		/// Constructing a String-In-Clause using <see cref="List{T}.Contains"/>.
		/// </summary>
		[Test]
		public void TestWhereStringInClause()
		{
			string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"in\"><value>scott</value><value>john</value></condition></filter></entity></fetch>";
			List<String> names = new List<String>() {"scott", "john"};
			var contactsWithNames = from c in provider.Linq<contact>()
									where names.Contains(c.firstname)
									select c;
            AssertXmlEquals(expectedXml, contactsWithNames);
		}

		/// <summary>
		/// steffana
		/// Constructing a Guid-In-Clause using <see cref="List{T}.Contains"/>.
		/// </summary>
		[Test]
		public void TestWhereGuidInClause()
		{
			string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"contactid\" operator=\"in\"><value>287d9bdd-ab75-dc11-ba22-0003ffbe21cc</value><value>7c5729e5-36a2-db11-8aa1-0003ffbe21cc</value></condition></filter></entity></fetch>";
			List<Guid> guids = new List<Guid>()
			                   	{
			                   		new Guid("287D9BDD-AB75-DC11-BA22-0003FFBE21CC"),
			                   		new Guid("7C5729E5-36A2-DB11-8AA1-0003FFBE21CC")
			                   	};
			var contactsWithNames = from c in provider.Linq<contact>()
									where guids.Contains(c.contactid.Value)
									select c;
            AssertXmlEquals(expectedXml, contactsWithNames);
		}

		/// <summary>
		/// steffana
		/// Constructing an String-In-Clause using <see cref="List{T}.Contains"/> - with join.
		/// </summary>
		[Test]
		public void TestJoinWhereStringInClause()
		{
			string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><all-attributes /><filter><condition attribute=\"firstname\" operator=\"in\"><value>scott</value><value>john</value></condition></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
			List<String> names = new List<String>() { "scott", "john" };
			var contactsWithNames = from c in provider.Linq<contact>()
			                        join a in provider.Linq<account>()
			                        	on c.parentcustomerid.Value equals a.accountid.Value
			                        where names.Contains(c.firstname)
			                        select c;
            AssertXmlEquals(expectedXml, contactsWithNames);
		}

		/// <summary>
		/// steffana
		/// Constructing an String-In-Clause on joined using <see cref="List{T}.Contains"/> - with join.
		/// </summary>
		[Test]
		public void TestJoinWhereStringInClauseOnJoined()
		{
			string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <all-attributes />
                        <filter>
                            <condition attribute=""firstname"" operator=""in"">
                                <value>scott</value>
                                <value>john</value>
                            </condition>
                        </filter>
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"">
                            <filter>
                                <condition attribute=""accountid"" operator=""in"">
                                    <value>287d9bdd-ab75-dc11-ba22-0003ffbe21cc</value>
                                    <value>7c5729e5-36a2-db11-8aa1-0003ffbe21cc</value>
                                </condition>
                            </filter>
                        </link-entity>
                    </entity>
                </fetch>";
			List<String> names = new List<String>() {"scott", "john"};
			List<Guid> guids = new List<Guid>()
			                   	{
			                   		new Guid("287D9BDD-AB75-DC11-BA22-0003FFBE21CC"),
			                   		new Guid("7C5729E5-36A2-DB11-8AA1-0003FFBE21CC")
			                   	};
            var contactsWithNames = from c in provider.Linq<contact>()
                                    join a in provider.Linq<account>()
                                        on c.parentcustomerid.Value equals a.accountid.Value
                                    where guids.Contains(a.accountid.Value) && names.Contains(c.firstname)
                                    select c;
            AssertXmlEquals(expectedXml, contactsWithNames);
        }

		//[Test]
        //public void TestInnerQuery()
        //{
        //    var contacts = from c in provider.Linq<contact>()
        //                   select new 
        //                   {
        //                       c.firstname,
        //                       Accounts = from a in provider.Linq<account>()
        //                       where a.primarycontactid.Value == c.contactid.Value
        //                       select a
        //                   };
        //    foreach (var v in contacts)
        //    {
        //        foreach (account a in v.Accounts) { }
        //    }
        //}

        [Test]
        public void TestManyJoins()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""salesorderdetail"">
                    <all-attributes />
                    <link-entity name=""salesorder"" from=""salesorderid"" to=""salesorderid"">
                      <link-entity name=""pricelevel"" from=""pricelevelid"" to=""pricelevelid"">
                        <link-entity name=""productpricelevel"" from=""pricelevelid"" to=""pricelevelid"" />
                      </link-entity>
                    </link-entity>
                  </entity>
                </fetch>
                ";

            var items = from item in provider.Linq<salesorderdetail>()
                        join so in provider.Linq<salesorder>() on item.salesorderid.Value equals so.salesorderid.Value
                        join pl in provider.Linq<pricelevel>() on so.pricelevelid.Value equals pl.pricelevelid.Value
                        join ppl in provider.Linq<productpricelevel>() on pl.pricelevelid.Value equals ppl.pricelevelid.Value
                        select item;

            AssertXmlEquals(expectedXml, items);
        }


        [Test]
        public void TestOrAndOr()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""contact"">
                    <all-attributes />
                        <filter>
                            <filter type=""or"">
                                <condition attribute=""firstname"" operator=""eq"" value=""test"" />
                                <condition attribute=""firstname"" operator=""eq"" value=""test2"" />
                            </filter>
                            <filter type=""or"">
                                <condition attribute=""accountrolecode"" operator=""eq"" value=""1"" />
                                <condition attribute=""accountrolecode"" operator=""eq"" value=""2"" />
                            </filter>
                    </filter>
                  </entity>
                </fetch>
                ";
            var contacts = from c in provider.Linq<contact>()
                        where (c.firstname == "test" || c.firstname == "test2") &&
                              (c.accountrolecode.Value == 1 || c.accountrolecode.Value == 2)
                        select c;
            AssertXmlEquals(expectedXml,contacts);
        }

        [Test]
        public void TestWhereWhere()
        {
            var expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""contact"">
                    <all-attributes />
                        <filter>
                            <condition attribute=""statecode"" operator=""eq"" value=""0"" />
                            <condition attribute=""contactid"" operator=""eq"" value=""00000000-0000-0000-0000-000000000000"" />
                            <filter type=""or"">
                                <condition attribute=""firstname"" operator=""eq"" value=""test"" />
                                <condition attribute=""firstname"" operator=""eq"" value=""test2"" />
                            </filter>
                            <filter type=""or"">
                                <condition attribute=""accountrolecode"" operator=""eq"" value=""1"" />
                                <condition attribute=""accountrolecode"" operator=""eq"" value=""2"" />
                            </filter>                        
                    </filter>
                    </entity>
                </fetch>
                ";

            Expression<Func<contact, bool>> expression = c => (c.firstname == "test" || c.firstname == "test2") &&
                                                              (c.accountrolecode.Value == 1 ||
                                                               c.accountrolecode.Value == 2);
            var actual = provider.Linq<contact>().Where(c => c.statecode.Value == ContactState.Active);
            actual = actual.Where(expression);
            var foobar = actual.
                Where(c => c.contactid.Value == Guid.Empty);
            AssertXmlEquals(expectedXml,foobar);
        }

    }
}
